package set_;

import java.util.HashSet;

/**
 * @Author 小闽
 * @Date 2024/11/2 16:45
 * @PackageName: set_
 * @ClassName: HashSetSource
 * @Description:
 * @Version
 */
@SuppressWarnings({"all"})
public class HashSetSource {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add("java");
        hashSet.add("php");
        hashSet.add("java");
        System.out.println("set= " + hashSet);

        // 1. 对HashSet源码的理解
        // 1. 先执行构造方法
        /*
            public HashSet() {
                map = new HashMap<>();
            }
         */
        // 2. 执行add方法
        /*
            public boolean add(E e) {  // e = "java"
                return map.put(e, PRESENT)==null;  //  (static) PRESENT = new Object();
            }
         */
        // 3. 执行put方法
        /*
            public V put(K key, V value) { // key: "java"  value = PRESENT 共享
                return putVal(hash(key), key, value, false, true);
            }
         */
       // 4. 执行has方法
        /*
          static final int hash(Object key) { // key: "java"
                int h;
                // 这里使用了一个三元运算符，判断key是否空，如果不为空,就通过算法计算值传进来的key对应的hash值
                return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
          }
         */
        // 5. 执行 putVal
        /*
                  final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                           boolean evict) {
                Node<K,V>[] tab; Node<K,V> p; int n, i; // 定义了辅助变量
                // table就是 HashMap的一个数组，类型是Node[]
                // if语句中的table是HashMap底层中一个属性，表示当前table为null,或者是0，
                // 就会进行第一次的扩容操作，并且扩容的大小为16
                if ((tab = table) == null || (n = tab.length) == 0)
                    n = (tab = resize()).length;
                 //（1）根据key得到的hash去计算该key应该存放到table表的哪个索引位置
                 // 并把这个位置的对象赋给p
                 //（2）判断p是否为null
                 //  （2.1） 如果p为null,表示当前数组中的位置还没有对象或元素，
                 // tab[i] = newNode(hash, key, value, null)
                 //就会先创建一个结点把key对应的元素给放到当前的位置当中去
                if ((p = tab[i = (n - 1) & hash]) == null)
                    tab[i] = newNode(hash, key, value, null);
                else {
                // 一个开发技巧提示：在需要局部变量（辅助变量）时候，再创建
                    Node<K,V> e; K k;
                    // 如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
                    // 并且满足下面两个条件之一：
                    //(1) 准备加入的 key 和 p 指向的Node结点的 key是同一个对象
                    //(2) p指向的Node结点的key的equals()和准备加入的key比较后相同
                    // 就不能加入
                    if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                        e = p;
                    // 再判断 p 是不是一颗红黑树，
                    // 如果是一颗红黑树，就调用 putTreeVal,来进行添加
                    else if (p instanceof TreeNode)
                        e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                    else {// 如果table对应索引位置，已经是一个链表，就使用for循环比较
                          // (1) 依次和该链表的每一个元素比较后，都不相同，则加入到该链表的最后
                          // 注意： 在把元素添加到链表后，立即判断该链表是否已经达到8个结点
                          //        就调用treeifyBin() 对当前这个链表进行树化（转成红黑树）
                          // 注意： 转成红黑树的同时，要进行判断，判断条件
                             if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                                   resize();
                            如果上面条件成立，先table扩容
                            // 只有上面条件不成立时，才进行转成红黑树
                          // (2) 依次和该链表的每一个元素比较过程中，如果有相相同情况，就直接break
                        for (int binCount = 0; ; ++binCount) {
                            if ((e = p.next) == null) {
                                p.next = newNode(hash, key, value, null);
                                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                    treeifyBin(tab, hash);
                                break;
                            }
                            if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                                break;
                            p = e;
                        }
                    }
                    if (e != null) { // existing mapping for key
                        V oldValue = e.value;
                        if (!onlyIfAbsent || oldValue == null)
                            e.value = value;
                        afterNodeAccess(e);
                        return oldValue;
                    }
                }
                ++modCount;
                if (++size > threshold)
                    resize();
                afterNodeInsertion(evict);
                return null;
            }
         */
    }
}
